<?php
/*******************************************************
 所有后台功能都需要加载该模块功能  单机模式
 *******************************************************/
namespace src\logic;
use \classlib\acl;
use classlib\input;
use \classlib\core as C;
use classlib\acl\acl_abstract;
class upfile {
	const  UPFILE_DIR = '/upfile';
	const  CRYPT_MLEN = 8092;
	const SM          = '_sm';
	/**
	 * 登录凭证信息
	 * @var acl_abstract
	 */
	private $acl;
	
	private $res;
	
	/**
	 * 单例模式获取对象信息
	 * @param upfile $acl
	 */
	public static function inst($acl=null) {
		static $upfile = null;
		if (!$upfile) {
			$upfile = new upfile($acl);
		}
		return $upfile;
	}
	
	/**
	 * 构造函数初始化
	 * @param acl_abstract $acl
	 */
	public function __construct($acl) {
		$this->acl = $acl;
		$this->res = array();
	}
	
	/**
	 * 获取请求的基础地址
	 * @return string
	 */
	private static function get_server() {
		$addr = (isset($_SERVER['REQUEST_SCHEME'])? $_SERVER['REQUEST_SCHEME']:'http').'://';
		$addr.= isset($_SERVER['SERVER_ADDR'])? $_SERVER['SERVER_ADDR']:'127.0.0.1';
		$addr.= ':'.(isset($_SERVER['SERVER_PORT'])? $_SERVER['SERVER_PORT']:'80');
		return $addr;
	}
	
	/**
	 * POST方式直接上传文件
	 * @param string $pkey
	 */
	public function post($pkey = 'upfile') {
		if (isset($_FILES[$pkey]) && is_uploaded_file($_FILES[$pkey]['tmp_name'])
			&& $_FILES[$pkey]['error'] == 0) { //检查确保上传的文件没有出错
			$subfix = substr($_FILES[$pkey]['type'], strpos($_FILES[$pkey]['type'], '/')+1);
			$this->transfer($_FILES[$pkey]['tmp_name'], 1, $_FILES[$pkey]['name'], $subfix);
			return $this->res;
		}
		return false;
	}
	
	/**
	 * 会员base64上传模式
	 * @param string $pkey
	 */
	public function base64($pkey = 'upfile') {
		$src = input::post('upfile');
		if (preg_match('/^data:([\;]+);base64,(.+)/i', $src, $res)) {
			$subfix = substr($res[1], strpos($res[1], '/')+1);
			$src    = base64_decode($res[2]);
			$name   = input::get_post('__name');
			empty($name) && $name = 'Base64';
			$this->transfer($src, 0, $name, $subfix);
		}
		return $this->res;
	}
	
	/**
	 * 会员二进制上传文件模式
	 * @param string $src
	 */
	public function binary($src='') {
		(!$src) && $src = input::stream();
		if ($src) {
			$subfix     = '.unknow';
			if (isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE']) {
				$subfix = substr($_SERVER['CONTENT_TYPE'], strpos($_SERVER['CONTENT_TYPE'], '/')+1);
			}
			$this->transfer($src, 0, 'Stream', $subfix);
		}
		return $this->res;
	}
	
	/**
	 * 针对文件头部分信息加密处理
	 * @param unknown $vcode
	 * @param unknown $file
	 */
	public function encrypt($vcode, $file) {
		$fp   = fopen($file, 'r+');
		$size = filesize($file);
		if ($size > self::CRYPT_MLEN) {
			$size = self::CRYPT_MLEN;	
		}
		$buffer = fread($fp, $size);
		if (!$vcode || !$buffer || $size != strlen($buffer)) {
			return;
		}
		$nlen   = strlen($vcode);
		for ($i=0; $i < $size; $i++) {
			$buffer[$i] = chr(ord($buffer[$i]) ^ ord($vcode[$i%$nlen]));
		}
		fseek($fp, 0, SEEK_SET);
		fwrite($fp, $buffer, $size);
		fclose($fp);
	}
	
	/**
	 * 文件解码输出流信息
	 * @param unknown $vcode
	 * @param unknown $file
	 */
	public function decrypt($vcode, $file) {
		$fp   = fopen($file, 'r');
		$size = filesize($file);
		if ($size > self::CRYPT_MLEN) {
			$size = self::CRYPT_MLEN;	
		}
		$buffer = fread($fp, $size);
		if ($vcode && $buffer || $size == strlen($buffer)) {
			$nlen   = strlen($vcode);
			for ($i=0; $i < $size; $i++) {
				$buffer[$i] = chr(ord($buffer[$i]) ^ ord($vcode[$i%$nlen]));
			}
		}
		echo $buffer;
		while (!feof($fp)) {
			echo fread($fp, self::CRYPT_MLEN);
		}
	}
	
	/**
	 * 上传文件
	 * @param string $src 文件流或者临时文件
	 * @param int    $ori 类型 1-临时文件 0-流文件
	 * @param string $name 文件名称
	 * @param string $subfix 后缀
	 * @throws \Exception
	 */
	private function transfer($src, $ori, $name, $subfix) {
		$dest = WEBROOT.self::UPFILE_DIR.'/'.date('Ym').'/'.mt_rand(1000, 9999).'/'.mt_rand(1000, 9999);
		if (!is_dir($dest)) {
			mkdir($dest, 0777, true);
		}
		$dest.= '/'.C\rand_str(8).'.'.$subfix;
		if ($ori == 1 && !move_uploaded_file($src, $dest)) { //文件上传且出现错误
			@unlink($src);
			throw new \Exception('Move upload file error.', 500);
		}
		if ($ori == 0 && !file_put_contents($dest, $src)) { //流文件写入出现错误的时候
			throw new \Exception('Stream upload file error.', 500);
		}
		$user  = ($this->acl)? $this->acl->user:array('id'=>0, 'nick'=>'匿名');
		$vcode = '';
		if (input::get_post('___crypt')) {
			$vcode = C\rand_str(8);
			$this->encrypt($vcode, $file);
		}
		$size  = filesize($dest);
		$type  = (int)input::get_post('___type');
		$origin= input::get_post('___origin');
		$score = (int)input::get_post('___score');
		($score < 1) && $score = 0;
		$coin  = (int)input::get_post('___coin');
		($coin < 0) && $coin = 0;
		$srv   = $this->get_server();
		$url   = substr($dest, strlen(WEBROOT));
		$field = array('userid'=>$user['id'], 'nick'=>$user['nick'], 'name'=>$name, 'vcode'=>$vcode, 
			'url'=>$url, 'type'=>$type, 'channel'=>$origin, 'score'=>$score, 'server'=>$srv,
			'coin'=>$coin, 'status'=>0, 'size'=>$size, 'ttlsize'=>$size, 'stime'=>C\config::$nowtime);
		$id    = C\model::load('main.sys.upfile')->new_one($field);
		$this->res = array('url'=>$url, 'id'=>$id);
	}
	
	/**
	 * 验证一个用户是否拥有该hash
	 * @param int $id
	 * @param string $vcode
	 * @return string
	 */
	public function hash($id, $vcode) {
		$userid = $this->acl->user? $this->acl->user['id']:0;
		return substr(md5($userid.$id.$vcode), 0, 16);
	}
	
	/**
	 * 获取文件的格式信息
	 * @param string $url
	 * @return string
	 */
	public function subfix($url) {
		$subfix = substr($url, strrpos($url, '.')+1);
		return $subfix;
	}
	
	/**
	 * 获取缩略图或者原图地址
	 * @param string $src
	 * @param string $isnail
	 * @return string
	 */
	public function thumburl($src, $isnail=true) {
		return ($isnail)? str_replace('.', self::SM.'.', $src):str_replace(self::SM.'.', '.', $src);		
	}
	
	/**
	 * 将置顶的图生成缩略图
	 * @param string $src
	 * @param mix    $scope
	 * @return bool or string
	 */
	public function thumbnail($src, $scope=2) {
		$src   = WEBROOT.$src;
		$size  = getimagesize($src);
		if (is_numeric($scope)) {
			$scope = array('w'=>$size[0]/$scope, 'h'=>$size[1]/$scope);
		}
		$nfile = $this->thumburl($src);
		if ($size[0] < $scope['w'] && $size[1] < $scope['h']) {
			copy($src, $nfile);
		} else {
			$subfix     = strtolower(substr($size['mime'], 6));
			$srcimg     = null;
			if (strcmp($subfix, 'jpg') == 0 || strcmp($subfix, 'jpeg') == 0) {
				$srcimg = imagecreatefromjpeg($src);
			} else if(strcmp($subfix, 'png') == 0) {
				$srcimg = imagecreatefrompng($src);
			} else if(strcmp($subfix, 'gif') == 0) {
				$srcimg = imagecreatefromgif($src);
			} else  {
				return false;
			}
			$newimg     = imagecreatetruecolor($scope['w'], $scope['h']);
			imagealphablending($newimg, false);
			imagesavealpha($newimg, true);
			imagecopyresampled($newimg, $srcimg, 0, 0, 0, 0, $scope['w'], $scope['h'], $size[0], $size[1]);
			//保存图片
			if (strcmp($subfix, 'jpg') == 0 || strcmp($subfix, 'jpeg') == 0) {
				imagejpeg($newimg, $nfile);
			} else if(strcmp($subfix, 'png') == 0) {
				imagepng($newimg, $nfile);
			} else if(strcmp($subfix, 'gif') == 0) {
				imagegif($newimg, $nfile);
			}
			imagedestroy($newimg);
			imagedestroy($srcimg);
		}
		$url   = substr($nfile, strlen(WEBROOT));
		return $url;
	}
	
	/**
	 * 验证文件是否存在，不存在的话会抓取一张过来
	 * @param string $ip
	 * @param port   $port
	 * @param string $srv
	 * @param string $path
	 * @param bool $ssl
	 */
	public function sync($ip, $port, $srv, $path, $ssl=false) {
		$url  = ($ssl? 'https://':'http://').$ip.':'.$port.$path;
		$ch   = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		if ($ssl) {
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //信任任何证书
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); //检查证书中是否设置域名
		}
		$header = array('HOST:'.$srv);
		curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3);
		curl_setopt($ch, CURLOPT_TIMEOUT, 30);
		$file = WEBROOT.$path;
		$dir  = dirname($file);
		if (!is_dir($dir)) {
			mkdir($dir, 0777, true);
		}
		$fp = fopen($file, 'w');
		curl_setopt($ch, CURLOPT_FILE, $fp);
		$ret  = curl_exec($ch);
		$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
		curl_close($ch);
		fclose($fp);
	}
}